import { PerspectiveCamera, Scene, WebGLRenderer } from 'three';
import { createCamera } from './components/camera';
import { createScene } from './components/scene';
import { createRenderer } from './systems/renderer';
import { createCube, createTransformCube } from './components/cube';
import { createHemisphereLight, createLights, createMultiLights } from './components/lights';
import { Resizer } from './systems/Resizer';
import { Loop } from './systems/Loop';
import { createControls } from './systems/controls';
import { createMeshGroup } from './components/meshGroup';
import { loadBirds } from './components/birds/birds';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js';
class TransformWorld {
  scene: Scene;
  camera: PerspectiveCamera;
  renderer: WebGLRenderer;

  constructor(container: HTMLElement) {
    this.scene = createScene();
    this.camera = createCamera();
    this.renderer = createRenderer();
    container.appendChild(this.renderer.domElement);

    const cube = createTransformCube();
    const light = createLights();

    this.scene.add(cube, light);
    const resizer = new Resizer(container, this.camera, this.renderer);
  }
  render() {
    const { scene, camera, renderer } = this;
    // draw a single frame
    renderer.render(scene, camera);
  }
}

class LightBasicWorld {
  scene: Scene;
  camera: PerspectiveCamera;
  renderer: WebGLRenderer;

  constructor(container: HTMLElement) {
    this.scene = createScene();
    this.camera = createCamera();
    this.renderer = createRenderer();
    container.appendChild(this.renderer.domElement);

    const cube = createCube();
    const light = createLights();

    this.scene.add(cube, light);

    const resizer = new Resizer(container, this.camera, this.renderer);
  }

  render() {
    const { scene, camera, renderer } = this;
    // draw a single frame
    renderer.render(scene, camera);
  }
}

/**
 * 如camera、renderer和scene一样，因为我们不希望从World类外部访问它：
 */
class BasicWorld {
  scene: Scene;
  camera: PerspectiveCamera;
  renderer: WebGLRenderer;
  loop: Loop;
  controls: OrbitControls;
  resizer: Resizer;
  constructor(container: HTMLElement) {
    const scene = createScene();
    const camera = createCamera();
    const renderer = createRenderer();
    const loop = new Loop(camera, scene, renderer);
    container.appendChild(renderer.domElement);

    const controls = createControls(camera, renderer.domElement);
    const { ambientLight, mainLight } = createHemisphereLight();
    const meshGroup = createMeshGroup();

    loop.updatables.push(controls, meshGroup);
    scene.add(ambientLight, mainLight, meshGroup);

    const resizer = new Resizer(container, camera, renderer);

    this.scene = scene;
    this.camera = camera;
    this.renderer = renderer;
    this.loop = loop;
    this.controls = controls;
    this.resizer = resizer;
  }

  render() {
    const { scene, camera, renderer } = this;
    // draw a single frame
    renderer.render(scene, camera);
  }

  start() {
    const { loop } = this;
    loop.start();
  }
  stop() {
    const { loop } = this;
    loop.stop();
  }
  // 销毁 https://threejs.org/docs/#manual/zh/introduction/How-to-dispose-of-objects
  dispose() {
    // 几何体
    // 材质
    // 纹理
    // WebGLRender

    const { scene, renderer, controls, resizer } = this;
    renderer.setAnimationLoop(null);

    scene.traverse((child: any) => {
      // console.log(child.material);
      if (child.material) {
        child.material.dispose();
      }
      if (child.geometry) {
        child.geometry.dispose();
      }
      child = null;
    });

    // 场景中的参数释放清理或者置空等
    renderer.forceContextLoss();
    renderer.dispose();
    controls.dispose();
    resizer.dispose();
    scene.clear();
    //@ts-ignore
    this.scene = null;
    //@ts-ignore
    this.camera = null;
    //@ts-ignore
    this.controls = null;
    //@ts-ignore
    renderer.domElement = null;
    //@ts-ignore
    this.renderer = null;
  }
}

class AnimateWorld {
  scene: Scene;
  camera: PerspectiveCamera;
  renderer: WebGLRenderer;
  loop: Loop;
  controls: OrbitControls;
  resizer: Resizer;
  constructor(container: HTMLElement) {
    const camera = createCamera();
    const renderer = createRenderer();
    const scene = createScene();
    const loop = new Loop(camera, scene, renderer);
    container.append(renderer.domElement);

    const controls = createControls(camera, renderer.domElement);

    const { ambientLight, mainLight } = createMultiLights();

    loop.updatables.push(controls);
    scene.add(ambientLight, mainLight);

    const resizer = new Resizer(container, camera, renderer);

    this.scene = scene;
    this.camera = camera;
    this.renderer = renderer;
    this.loop = loop;
    this.controls = controls;
    this.resizer = resizer;
  }

  async init() {
    const { loop, scene, controls } = this;
    const { parrot, flamingo, stork } = await loadBirds();

    // move the target to the center of the front bird
    controls.target.copy(parrot.position);

    loop.updatables.push(parrot, flamingo, stork);
    scene.add(parrot, flamingo, stork);
  }

  render() {
    const { scene, camera, renderer } = this;
    renderer.render(scene, camera);
  }

  start() {
    const { loop } = this;
    loop.start();
  }

  stop() {
    const { loop } = this;
    loop.stop();
  }
  // 销毁 https://threejs.org/docs/#manual/zh/introduction/How-to-dispose-of-objects
  dispose() {
    // 几何体
    // 材质
    // 纹理
    // WebGLRender

    const { scene, renderer, controls, resizer } = this;
    renderer.setAnimationLoop(null);

    scene.traverse((child: any) => {
      // console.log(child.material);
      if (child.material) {
        child.material.dispose();
      }
      if (child.geometry) {
        child.geometry.dispose();
      }
      child = null;
    });

    // 场景中的参数释放清理或者置空等
    renderer.forceContextLoss();
    renderer.dispose();
    controls.dispose();
    resizer.dispose();
    scene.clear();
    //@ts-ignore
    this.scene = null;
    //@ts-ignore
    this.camera = null;
    //@ts-ignore
    this.controls = null;
    //@ts-ignore
    renderer.domElement = null;
    //@ts-ignore
    this.renderer = null;
  }
}


export { LightBasicWorld, TransformWorld, BasicWorld, AnimateWorld };
